/*
 * Copyright (c) 2007 InfoReach, Inc. All Rights Reserved.
 *
 * This software is the confidential and proprietary information of
 * InfoReach ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with InfoReach.
 *
 * CopyrightVersion 2.0
 *
 */
package com.inforeach.util.string;

import java.util.Arrays;
import java.util.Iterator;

/**
 * 
 * @author dmytros
 */
public class StringSequenceGenerator implements Iterable<String>
{
    private final char[] alphabet_;
    private final int[] initial_;

    public StringSequenceGenerator(String alphabet)
    {
        this(alphabet, "");
    }

    public StringSequenceGenerator(String alphabet, String initial)
    {
        alphabet_ = prepareAlphabet(alphabet);
        initial_ = prepareInitial(alphabet, initial);
    }

    static char[] prepareAlphabet(String alphabet)
    {
        if (alphabet.isEmpty())
        {
            throw new IllegalArgumentException("Alphabet is empty");
        }
        char[] result = alphabet.toCharArray();
        char[] test = result.clone();
        Arrays.sort(test);
        for (int i = 1, n = test.length; i < n; ++i)
        {
            if (test[i - 1] == test[i])
            {
                throw new IllegalArgumentException("There is duplicate <" + test[i] + "> in the alphabet <"
                        + alphabet + ">");
            }
        }
        return result;
    }

    static int[] prepareInitial(String alphabet, String initial)
    {
        int n = initial.length();
        int[] result = new int[n];
        for (int i = 0; i < n; ++i)
        {
            char ch = initial.charAt(i);
            int index = alphabet.indexOf(ch);
            if (index < 0)
            {
                throw new IllegalArgumentException("There is character <" + ch + "> of <" + initial
                        + "> that is not present in the alphabet <" + alphabet + ">");
            }
            result[i] = index;
        }
        return result;
    }

    @Override
    public Iterator<String> iterator()
    {
        return new Itr(alphabet_, initial_);
    }

    static class Itr implements Iterator<String>
    {
        private final char[] alphabet_;
        private int[] current_;

        Itr(char[] alphabet, int[] initial)
        {
            alphabet_ = alphabet;
            current_ = initial.clone();
        }

        @Override
        public String next()
        {
            String result = current();
            final int limit = alphabet_.length;
            boolean carry = true;
            int pos = current_.length;
            while (carry && --pos >= 0)
            {
                carry = false;
                if (++current_[pos] == limit)
                {
                    carry = true;
                    current_[pos] = 0;
                }
            }
            if (carry)
            {
                current_ = new int[current_.length + 1];
            }
            return result;
        }

        String current()
        {
            int n = current_.length;
            char[] chars = new char[n];
            for (int i = 0; i < n; ++i)
            {
                chars[i] = alphabet_[current_[i]];
            }
            return new String(chars);
        }

        @Override
        public boolean hasNext()
        {
            return true;
        }

        @Override
        public void remove()
        {
            throw new UnsupportedOperationException();
        }
    }
}
